package com.ruoyi.bi.service.impl.model;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.bi.domain.common.RequestStatus;
import com.ruoyi.bi.domain.common.Result;
import com.ruoyi.bi.domain.model.Cube;
import com.ruoyi.bi.domain.model.Dimension;
import com.ruoyi.bi.domain.model.Measure;
import com.ruoyi.bi.mapper.model.*;
import com.ruoyi.bi.service.model.CubeService;
import com.ruoyi.bi.service.model.DimensionService;
import com.ruoyi.common.core.domain.AjaxResult;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author anan.
 * @version 1.0
 * @create 2021-05-12 13-51
 */
@Service
public class CubeServiceImpl extends ServiceImpl<CubeMapper,Cube> implements CubeService {

    private Logger log = Logger.getLogger(CubeService.class);

    @Autowired
    private CubeMapper cubeMapper;

    @Autowired
    private DimensionMapper dimensionMapper;

    @Autowired
    private DimensionService dimensionService;

    @Autowired
    private MeasureMapper kpiMapper;

    @Autowired
    private CubeColMetaMapper cubeColMetaMapper;

    @Autowired
    private DatasetMapper dsetMapper;

    @Override
    public List<Cube> listCube(String keyword){
        return cubeMapper.listCube(keyword);
    }

    @Override
    public Integer getMaxCubeId(){
        return cubeMapper.getMaxCubeId();
    }

    @Override
    public JSONObject getCubeById(Integer cubeId){
        Cube cube = cubeMapper.getCubeById(cubeId);
        JSONObject ret = (JSONObject) JSONObject.toJSON(cube);
        /** 查询字段 */
        String cfg = dsetMapper.getDatasetCfg(cube.getDsetId());
        JSONObject dset = JSONObject.parseObject(cfg);
        ret.put("cols", dset.get("cols"));
        ret.put("dynamic", dset.get("dynamic"));
        /** 查询维度 */
        ret.put("dims", cubeMapper.getCubeDims(cubeId));
        /** 查询度量 */
        ret.put("kpis", cubeMapper.getCubeKpis(cubeId));
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insertCube(Cube cube){
        try{
            Integer cubeId = cubeMapper.getMaxCubeId();
            cube.setCubeId(cubeId);
            cubeMapper.insert(cube);
            this.insertDim(cube);
            this.insertDimRela(cube);
            this.insertKpi(cube);
            this.insertKpiRela(cube);
            return AjaxResult.success();
        }
        catch(Exception ex){
            log.error("", ex);
            return AjaxResult.error("立方体保存出错。");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result deleteCube(Integer cubeId){
        Result ret = new Result();
        try{
            /** 删除表 */
            cubeMapper.deleteCube(cubeId);
            cubeColMetaMapper.deleteByCubeId(cubeId);
            /** 删除指标 */
            Measure kpi = new Measure();
            kpi.setCubeId(cubeId);
            kpiMapper.deleteKpi(kpi);
            /** 删除维度 */
            Dimension dim = new Dimension();
            dim.setCubeId(cubeId);
            dimensionMapper.deleteDim(dim);
            /** 删除分组 */
            dimensionMapper.deleteGroupByCubeId(cubeId);
            ret.setResult(RequestStatus.SUCCESS.getStatus());
        }catch(Exception ex){
            ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
            ret.setMsg(ex.getMessage());
            log.error("立方体保存出错。", ex);
        }
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result updateCube(Cube cube){
        Result ret = new Result();
        try{
            cubeMapper.updateCube(cube);
            /** 在编辑立方体时，通过delObj 来描述哪些维度，度量、分组被删除掉了。先第一步删除这些 */
            List<Map<String, Object>> dels = cube.getDelObj();
            for(int i=0; dels!=null&&i<dels.size(); i++){
                Map<String, Object> obj = dels.get(i);
                Object tp = obj.get("type");
                Object id = obj.get("id");
                if(id == null || id.toString().length() == 0){
                    continue;
                }
                if("dim".equals(tp)){
                    Dimension dim = new Dimension();
                    dim.setCubeId(cube.getCubeId());
                    dim.setDimId((Integer)id);
                    dimensionMapper.deleteDim(dim);
                }else if("kpi".equals(tp)){
                    Measure kpi = new Measure();
                    kpi.setCubeId(cube.getCubeId());
                    kpi.setKpiId((Integer)id);
                    kpiMapper.deleteKpi(kpi);
                }else if("group".equals(tp)){
                    dimensionMapper.deleteGroupById((String)id);
                }
            }

            /** 删除关系表数据，再从建 */
            /** 处理维度 */
            this.updateDim(cube);
            this.insertDimRela(cube);
            /** 处理指标 */
            this.updateKpi(cube);
            this.insertKpiRela(cube);
            ret.setResult(RequestStatus.SUCCESS.getStatus());
        }catch(Exception ex){
            ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
            ret.setMsg(ex.getMessage());
            log.error("立方体保存出错。", ex);
        }
        return ret;
    }

    @Override
    public void updateDim(Cube cube){
        List<String> groupkeys = dimensionMapper.listGroup(cube.getCubeId());
        List<Dimension> dims = cube.getDims();
        for(int i=0; i<dims.size(); i++){
            Dimension dim = dims.get(i);
            dim.setCubeId(cube.getCubeId());
            dim.setOrd(i);
            String type = dim.getType();
            if(type == null || type.length() == 0){
                dim.setType("frd");
            }
            /** 判断是否有分组，如果有分组插入分组 */
            String groupId = dim.getGroupId();
            if(groupId != null && groupId.length() > 0 && !groupkeys.contains(groupId)){
                dimensionMapper.insertGroup(dim);
                groupkeys.add(groupId);
            }
            Integer targetId = dim.getTargetId();
            if(targetId == null){
                /** 新增维度 */
                dimensionMapper.insertDim(dim);
                targetId = dimensionMapper.getMaxDimId();
            }else{
                /** 修改维度 */
                String isupdate = dim.getIsupdate();
                if("y".equals(isupdate)){
                    /** 只有修改过的维度才更新 */
                    dimensionMapper.updatedim(dim);
                }
            }
            dim.setDimId(targetId);
        }
    }

    @Override
    public void updateKpi(Cube cube){
        List<Measure> kpis = cube.getKpis();
        for(int i=0; i<kpis.size(); i++){
            Measure kpi = kpis.get(i);
            kpi.setCubeId(cube.getCubeId());
            Integer targetId = kpi.getTargetId();
            if(targetId == null){
                /** 新增 */
                kpiMapper.insertKpi(kpi);
                targetId = kpiMapper.getMaxKpiId();
            }else{
                /** 修改 */
                String isupdate = kpi.getIsupdate();
                if("y".equals(isupdate)){
                    kpiMapper.updateKpi(kpi);
                }
            }
            kpi.setKpiId(targetId);
        }
    }

    @Override
    public void insertDim(Cube cube){
        List<String> groupkeys = new ArrayList<String>(16);
        List<Dimension> dims = cube.getDims();
        int dimId = 0;
        for(int i=0; i<dims.size(); i++){
            Dimension dim = dims.get(i);
            dim.setOrd(i);
            String type = dim.getType();
            if(type == null || type.length() == 0){
                dim.setType("frd");
            }
            dim.setCubeId(cube.getCubeId());
            dimensionService.save(dim);
            if(i == 0){
                dimId = dimensionMapper.getMaxDimId();
            }else{
                dimId++;
            }
            /** 判断是否有分组，如果有分组插入分组 */
            String groupId = dim.getGroupId();
            if(groupId != null && groupId.length() > 0 && !groupkeys.contains(groupId)){
                dimensionMapper.insertGroup(dim);
                groupkeys.add(groupId);
            }
            dim.setDimId(dimId);
        }
    }

    @Override
    public void insertDimRela(Cube cube){
        cubeColMetaMapper.deleteDimMeta(cube.getCubeId());
        List<Dimension> dims = cube.getDims();
        for(int i=0; i<dims.size(); i++){
            Dimension dim = dims.get(i);
            dim.setColId(dim.getDimId());
            dim.setOrd(i);
            dim.setColType(1);
            cubeColMetaMapper.insert(dim);
        }
    }

    @Override
    public void insertKpi(Cube cube){
        int kpiId = 0;
        List<Measure> kpis = cube.getKpis();
        for(int i=0; i<kpis.size(); i++){
            Measure kpi = kpis.get(i);
            kpi.setCubeId(cube.getCubeId());
            kpiMapper.insert(kpi);
            if(i == 0){
                kpiId = kpiMapper.getMaxKpiId();
            }else{
                kpiId++;
            }
            kpi.setKpiId(kpiId);
        }
    }

    @Override
    public void insertKpiRela(Cube cube){
        /** 先删除指标数据 */
        cubeColMetaMapper.deleteKpiMeta(cube.getCubeId());
        List<Measure> kpis = cube.getKpis();
        for(int i=0; i<kpis.size(); i++){
            Measure kpi = kpis.get(i);
            kpi.setColId(kpi.getKpiId());
            kpi.setOrd(i);
            /** 如果指标不是计算指标，直接拼接，计算指标直接取公式 */
            /** 新增度量那创建的计算指标 */
            Integer calcKpi = kpi.getCalcKpi();
            /** 数据集创建的动态字段 */
            //int calc = kpi.getCalc();
            if(calcKpi==null || calcKpi == 0){
                kpi.setCol(kpi.getAggreCol());
            }else{
                kpi.setCol(kpi.getCol());
            }
            kpi.setColType(2);
            cubeColMetaMapper.insert(kpi);
        }
    }

    @Override
    public List<Map<String, Object>> treeCube(Integer cubeId){
        /** 当前分组对象. */
        Map<String, Object> curGroup = null;
        /** 默认所有节点都打开 */
        Map<String, Object> state = new HashMap<String, Object>(16);
        state.put("opened", true);
        List<Map<String, Object>> ls = cubeMapper.listDs(String.valueOf(cubeId));
        for(int i=0; i<ls.size(); i++){
            Map<String, Object> m = ls.get(i);
            m.put("icon", "fa fa-cubes");
            m.put("state", state);
            /** 给数据集节点添加维度、指标节点 */
            List<Map<String, Object>> cubeChild = new ArrayList<Map<String, Object>>(16);
            m.put("children", cubeChild);
            Map<String, Object> wdnode = new HashMap<String, Object>(16);
            wdnode.put("id", "wd");
            wdnode.put("text", "维度");
            wdnode.put("state", state);
            wdnode.put("icon", "fa fa-gears");
            List<Map<String, Object>> wdnodeChild = new ArrayList<Map<String, Object>>(16);
            wdnode.put("children", wdnodeChild);
            cubeChild.add(wdnode);
            Map<String, Object> zbnode = new HashMap<String, Object>(16);
            zbnode.put("id", "zb");
            zbnode.put("text", "度量");
            zbnode.put("state", state);
            zbnode.put("icon", "glyphicon glyphicon-signal");
            List<Map<String, Object>> zbnodeChild = new ArrayList<Map<String, Object>>(16);
            zbnode.put("children", zbnodeChild);
            cubeChild.add(zbnode);

            List<Map<String, Object>> children = cubeMapper.listCubeMeta(cubeId);

            /** 设置attributes */
            for(int j=0; j<children.size(); j++){
                Map<String, Object> child = (Map<String, Object>)children.get(j);
                Integer col_type = new Integer(child.get("col_type").toString());
                String grouptype = (String)child.get("grouptype");
                if(grouptype == null || grouptype.length() == 0){
                    grouptype = null;
                }
                String groupname = (String)child.get("groupname");
                if(grouptype != null && grouptype.length() > 0){
                    if(curGroup == null || !curGroup.get("id").equals(grouptype)){
                        /** 添加分组节点 */
                        Map<String, Object> fz = new HashMap<String, Object>(16);
                        fz.put("id", grouptype);
                        fz.put("text", groupname);
                        fz.put("state", state);
                        fz.put("icon", " glyphicon glyphicon-stop icon_dim");
                        fz.put("children", new ArrayList());
                        /** 给分组添加attributes (把分组的第一个节点信息传递给他,拖拽分组时就当拖拽第一个节点) */
                        Map<String, Object> attr = new HashMap<String, Object>(16);
                        fz.put("li_attr", attr);
                        attr.put("col_type", col_type);
                        attr.put("col_id", child.get("col_id"));
                        attr.put("col_name", child.get("col_name"));
                        attr.put("cubeId", child.get("cubeId"));
                        attr.put("dsetId", child.get("dsetId"));
                        attr.put("dsid", child.get("dsid"));
                        attr.put("alias", child.get("alias"));
                        attr.put("dim_type", child.get("dim_type"));
                        attr.put("tableName", child.get("tableName") == null ? "" : child.get("tableName"));
                        attr.put("tableColKey", child.get("tableColKey") == null ? "" : child.get("tableColKey"));
                        attr.put("tableColName", child.get("tableColName") == null ? "" : child.get("tableColName"));
                        attr.put("ordcol", child.get("ordcol") == null ? "" : child.get("ordcol"));
                        attr.put("dateformat", child.get("dateformat") == null ? "" : child.get("dateformat"));
                        attr.put("tname", child.get("tname"));
                        attr.put("calc", child.get("calc"));
                        if(curGroup == null){
                            attr.put("iscas", "");
                        }else{
                            attr.put("iscas", "y");
                        }
                        attr.put("dimord", child.get("dimord") == null ? "" : child.get("dimord"));
                        attr.put("grouptype", grouptype);
                        attr.put("valType", child.get("valType"));
                        wdnodeChild.add(fz);
                        curGroup = fz;
                    }
                }else{
                    curGroup = null;
                }
                Map<String, Object> attr = new HashMap<String, Object>(16);
                child.put("li_attr", attr);
                /** 添加立方体所使用的数据源到Tree */
                attr.put("col_type", col_type);
                attr.put("col_id", child.get("col_id"));
                attr.put("col_name", child.get("col_name"));
                attr.put("cubeId", child.get("cubeId"));
                attr.put("dsetId", child.get("dsetId"));
                attr.put("dsid", child.get("dsid"));
                attr.put("alias", child.get("alias"));
                attr.put("fmt", child.get("fmt") == null ? "" : child.get("fmt"));
                attr.put("aggre", child.get("aggre"));
                attr.put("dim_type", child.get("dim_type"));
                attr.put("tableName", child.get("tableName") == null ? "" : child.get("tableName"));
                attr.put("tableColKey", child.get("tableColKey") == null ? "" : child.get("tableColKey"));
                attr.put("tableColName", child.get("tableColName") == null ? "" : child.get("tableColName"));
                attr.put("dateformat", child.get("dateformat") == null ? "" : child.get("dateformat"));
                attr.put("tname", child.get("tname"));
                attr.put("calc", child.get("calc"));
                if(curGroup == null){
                    attr.put("iscas", "");
                }else{
                    attr.put("iscas", "y");
                }
                attr.put("dimord", child.get("dimord") == null ? "" : child.get("dimord"));
                attr.put("rate", child.get("rate"));
                attr.put("unit", child.get("unit") == null ? "" : child.get("unit"));
                attr.put("grouptype", grouptype);
                attr.put("calc_kpi", child.get("calc_kpi"));
                attr.put("valType", child.get("valType"));
                attr.put("ordcol", child.get("ordcol") == null ? "" : child.get("ordcol"));
                /** 设置节点图标 */
                if(col_type == 1){
                    if(grouptype == null || grouptype.length() == 0){
                        child.put("icon", "glyphicon glyphicon-stop icon_dim");
                    }else{
                        child.put("icon", "fa fa-th-large icon_dim");
                    }
                }else{
                    child.put("icon", "glyphicon glyphicon-stop icon_kpi");
                }
                if(col_type == 1){
                    if(curGroup == null){
                        wdnodeChild.add(child);
                    }else{
                        ((List)curGroup.get("children")).add(child);
                    }
                }else{
                    zbnodeChild.add(child);
                }
            }
        }
        return ls;
    }
}
